package com.onec.service.route.service.base;

import com.onec.service.api.dto.request.route.RouteReq;
import com.onec.service.api.enums.error.RouteErrorEnum;
import com.onec.service.api.exception.RouteException;
import com.onec.service.route.entity.TradeRuleInfo;
import com.onec.service.route.service.AgentLimitInfoService;
import com.onec.service.route.service.BlockInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author ONEC
 */
public abstract class BaseTradeConfigDefaultService implements TradeConfigBaseService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseTradeConfigDefaultService.class);


    @Autowired
    protected BlockInfoService blockInfoService;
    @Autowired
    protected AgentLimitInfoService agentLimitInfoService;

    @Resource
    protected RedisTemplate<String, Optional> redisTemplate;
    @Resource
    protected ZSetOperations<String, String> zSetOperations;


    /**
     * 交易业务类处理：
     *
     * @param routeReq
     * @return ResponseOnline
     */
    @Override
    public boolean afterExecute(RouteReq routeReq) {
        LOGGER.info("系统默认实现方法：onlineParam");
        return false;
    }

    /**
     * 商户业务类处理：
     *
     * @param
     * @return ResponseMerchant
     */
    @Override
    public boolean beforeExecute(RouteReq routeReq, TradeRuleInfo tradeRuleInfo) {
        LOGGER.info("系统默认实现方法：bizContent");
        return true;
    }

    /**
     * 验证商户日交易限额
     */
    protected void checkDayLimitAmount(String merchantDayKey, String dayLimitAmountKey, BigDecimal amount,
                                       BigDecimal ruleAmount) {
        Optional<Long> agentNoSource = Optional.ofNullable(zSetOperations.rank(merchantDayKey, dayLimitAmountKey));
        LOGGER.info("商户配置KEY：{}，日累计：当前累计条数：{}", merchantDayKey, agentNoSource);
        if (agentNoSource.isPresent()) {
            Double dayScore = Optional.ofNullable(zSetOperations.score(merchantDayKey, dayLimitAmountKey)).orElse(0.0);
            LOGGER.info("商户日限额验证：商户配置KEY：{}，累计金额：{}，配置金额：{}", merchantDayKey, dayScore, amount);
            BigDecimal totalAmount = amount.add(BigDecimal.valueOf(dayScore));
            if (totalAmount.compareTo(ruleAmount) > 0) {
                throw new RouteException(RouteErrorEnum.MERCHANT_DAY_AMOUNT_ERROR, totalAmount.toPlainString());
            }
        }

    }

    /**
     * 验证商户月交易限额
     */
    protected void checkMonthLimitAmount(String merchantMonthKey, String monthLimitAmountKey, BigDecimal amount,
                                         BigDecimal ruleAmount) {
        Optional<Long> monthLimitAmount = Optional.ofNullable(zSetOperations.rank(merchantMonthKey, monthLimitAmountKey));
        LOGGER.info("商户配置KEY：{}，月累计：当前累计条数：{}", merchantMonthKey, zSetOperations.score(merchantMonthKey, monthLimitAmountKey));
        if (monthLimitAmount.isPresent()) {
            Double monthScore = Optional.ofNullable(zSetOperations.score(merchantMonthKey, monthLimitAmountKey))
                    .orElse(0.0);
            LOGGER.info("商户月限额验证：商户配置KEY：{}，交易金额：{}，配置金额：{}", monthLimitAmount, amount, ruleAmount);
            BigDecimal totalAmount = amount.add(BigDecimal.valueOf(monthScore));
            if (totalAmount.compareTo(ruleAmount) > 0) {
                throw new RouteException(RouteErrorEnum.MERCHANT_MONTH_AMOUNT_LIMIT, totalAmount.toPlainString());
            }
        }
    }

    /**
     * 验证商户日交易笔数限制
     */
    protected void checkDayLimitCount(String merchantDayKey, String dayLimitCountKey, double ruleCount) {

        Optional<Long> dayCount = Optional.ofNullable(zSetOperations.rank(merchantDayKey, dayLimitCountKey));
        LOGGER.info("商户配置KEY：{}，日累计笔数：{}", merchantDayKey, zSetOperations.score(merchantDayKey, dayLimitCountKey));
        if (dayCount.isPresent()) {
            Double dayScore = Optional.ofNullable(zSetOperations.score(merchantDayKey, dayLimitCountKey)).orElse(0.0);
            LOGGER.info("商户日笔数验证：商户配置KEY：{}，累计笔数：{}，配置笔数：{}", merchantDayKey, dayScore, ruleCount);
            if (dayScore - ruleCount > 1) {
                throw new RouteException(RouteErrorEnum.MERCHANT_DAY_COUNT_LIMIT, dayScore.toString());
            }
        }
    }

    /**
     * 验证商户月交易笔数限制
     */
    protected void checkMonthLimitCount(String merchantMonthKey, String monthLimitCountKey, double ruleCount) {

        Optional<Long> dayCount = Optional.ofNullable(zSetOperations.rank(merchantMonthKey, monthLimitCountKey));
        LOGGER.info("商户配置KEY：{}，月累计笔数：{}", merchantMonthKey, zSetOperations.score(merchantMonthKey, monthLimitCountKey));
        if (dayCount.isPresent()) {
            Double monthScore = Optional.ofNullable(zSetOperations.score(merchantMonthKey, monthLimitCountKey)).orElse(0.0);
            LOGGER.info("商户月交易笔数验证：商户配置KEY：{}，月累计笔数：{}，配置笔数：{}", merchantMonthKey, monthScore, ruleCount);
            if (monthScore - ruleCount > 1) {
                throw new RouteException(RouteErrorEnum.MERCHANT_MONTH_COUNT_LIMIT, monthScore.toString());
            }
        }
    }

    /**
     * 月交易金额累加，笔数累加：
     */
    protected void addLimit(String merchantLimitKey, String valueKey, double score, long expireTime) {

        Optional<Long> dayCount = Optional.ofNullable(zSetOperations.rank(merchantLimitKey, valueKey));
        if (dayCount.isPresent()) {
            LOGGER.info("商户配置KEY：{}，限制累计：{}", merchantLimitKey, zSetOperations.score(merchantLimitKey, valueKey));
            zSetOperations.incrementScore(merchantLimitKey, valueKey, score);
        } else {
            zSetOperations.add(merchantLimitKey, valueKey, score);
            //new RedisTemplate<>().expire(merchantLimitKey, RedisKeyUtil.getExpireTime(), TimeUnit.SECONDS);
            LOGGER.info("当前第一笔：KEY:{}是否需要设置过期时间：当前过期时间为：{}", merchantLimitKey, expireTime);
            if (expireTime > 0) {
                redisTemplate.expire(merchantLimitKey, expireTime, TimeUnit.SECONDS);
            }
        }
    }

}
